/**
  ******************************************************************************
  * File Name          : CAT1tf.c
  * Description        : This file provides code for the configuration
  *                      of the CAT1tf instances.
  ******************************************************************************
  * @attention
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include "cat1.h"
#include "network.h"

#define UAT_KEYWORD    "^mK=6#"

//static const char Cat1_UatKey[8] = UAT_KEYWORD;

static const Cat1_ConfigParaTyp Cat1_CfgPara =
{
	.wkmod     = ":NET\r\n",  //HTTPD UDC
  .cmdpw     = ":"UAT_KEYWORD"\r\n",
  .stmsg     = "WH-GM5",
  .rstim     = ":3600\r\n",
  .spden     = ":OFF\r\n",
  .naten     = ":OFF\r\n",
  .uaten     = ":OFF\r\n",
  .cachen    = ":ON\r\n",
  .uartfl    = ":1024\r\n",   //50~60000
  .uartft    = ":100\r\n",   //1~4096
  .socka     = ":TCP,183.230.102.116,1883\r\n",
  .sockaen   = ":ON\r\n",     //OFF
	.sockben   = ":OFF\r\n",     //OFF
  .sockasl   = ":LONG\r\n",   //SHORT
	.sockrstim = ":60\r\n",  //0~65535
	.regen     = ":OFF\r\n",
	.hearten   = ":OFF\r\n",
};

QueueHandle_t cat1_cmdque_qhd = NULL;
static StaticQueue_t cat1_cmdque_stru;
static uint8_t       cat1_cmdque_area[ CAT1_CMDQUE_LENGTH * CAT1_CMDQUE_ITEMSIZE ];

static Cat1_CmdBufType cat1_cmdrcv_buf;   /* 接收buf 任务后端 */
static Cat1_CmdBufType cat1_cmdisr_Buf;   /* 接收buf 中断前端 */

static char tmpbf[CAT1_MAX_TMPBFLEN];     /* command payload string */

volatile Cat1_ModeType Cat1_WorkMode = CAT1_MODE_TRS;

Cat1_StaticInfoType  Cat1_StaticInfo;
Cat1_DynamicInfoType Cat1_DynamicInfo;

static void cat1_init(void)
{
  cat1_cmdque_qhd = xQueueCreateStatic(CAT1_CMDQUE_LENGTH, CAT1_CMDQUE_ITEMSIZE, \
	                                     cat1_cmdque_area, &cat1_cmdque_stru);
	Cat1_BspInit();
}

static uint8_t cat1_powerup_wait_stmsg(void)
{
	memset(&cat1_cmdrcv_buf, 0, sizeof(Cat1_CmdBufType));
	memset(&cat1_cmdisr_Buf, 0, sizeof(Cat1_CmdBufType));
	
	xQueueReset(cat1_cmdque_qhd);
  
	Cat1_WorkMode = CAT1_MODE_CMD;
  
	Cat1_Reset(1);
	Cat1_Power(1);

	if(xQueueReceive(cat1_cmdque_qhd, &cat1_cmdrcv_buf, 30000) == pdTRUE)
	{
		if(strstr((const char*)cat1_cmdrcv_buf.buf, Cat1_CfgPara.stmsg) != NULL)
		{
			Cat1_WorkMode = CAT1_MODE_TRS;
			
			return 0;
		}
		else
		{
			Cat1_WorkMode = CAT1_MODE_TRS;
			
			return (ERROR_PART1 + 1);
		}
	}
	
	Cat1_WorkMode = CAT1_MODE_TRS;
	
	return (ERROR_PART1 + 2);
}

/* multiple instances can be shared */
static Cat1_ErrTyp cat1_cmd_process(const Cat1_CommandTyp *cmd, const char *para)
{
	Cat1_ErrTyp res = CAT1_CMD_UNKNOWN2;
  int8_t cmd_retry;  /* 整条命令的重试 */
  int8_t res_retry;  /* 等待回复的重试 */
  char *p = NULL;
	
  cmd_retry = cmd->rty;
  res_retry = 3;
  
  while(cmd_retry-->0)
  {
		Cat1_WorkMode = CAT1_MODE_CMD;
		
		xQueueReset(cat1_cmdque_qhd);
		memset(&cat1_cmdrcv_buf, 0, sizeof(Cat1_CmdBufType));
		memset(&cat1_cmdisr_Buf, 0, sizeof(Cat1_CmdBufType));
		
		/* send cmd */
		if(cmd->cmdtype == SET_PARA)
		{
			if((strlen(cmd->cstr) + strlen(para)) > (CAT1_MAX_TMPBFLEN-1))
			{
				res = CAT1_CMD_ERRPARA;
				goto cmd_process_return;
			}
			
			memset(tmpbf, 0, CAT1_MAX_TMPBFLEN);
			strncpy(tmpbf, cmd->cstr, CAT1_MAX_TMPBFLEN);
			strncat(tmpbf, (para+1), CAT1_MAX_TMPBFLEN);
			
			Cat1_UartSendStr(tmpbf);
		}
		else
		{
			Cat1_UartSendStr(cmd->cstr);
		}
		
		/* waiting for reply 等待超时直接退出循环,如果收到错的回复(有数据接收,但关键词匹配不成功的情况),则从新等待接收 */
    while((xQueueReceive(cat1_cmdque_qhd, &cat1_cmdrcv_buf, cmd->timout) == pdTRUE) && (res_retry-- > 0))
    {
      /* empty buffer */
			if(cat1_cmdrcv_buf.count == 0x00) 
			{
				continue;
			}
			
			p = strstr((const char*)cat1_cmdrcv_buf.buf, cmd->rstr);
			if(p != NULL)  /* keyword match successful */
			{
				if((cmd->cmdtype == SET_PARA) || (cmd->cmdtype == SIMPLE_INS))
				{
					res = CAT1_CMD_OK;
					goto cmd_process_return;
				}
				
				p = strchr(p, ':');  /* offset to parameter */
        if(p == NULL)
        {
          break;  /* 找不到冒号的情况 大概率是收到乱七八糟的东西了 重试发送 */
        }
        
				if(cmd->cmdtype == CHECK_PARA)
				{
					if(strstr(p, para) != NULL)
					{
						res = CAT1_CMD_OK;
					}
					else /* parameter matching failed, return withont retry */
					{
						res = CAT1_CMD_ERRCHECK;
					}
					
					goto cmd_process_return;
				}
				
				if(cmd->cmdtype == QUERY_STAT)
				{
					*(strchr(p+1, '\r')) = 0;
					memset(tmpbf, 0, CAT1_MAX_TMPBFLEN);
					strncpy(tmpbf, p+1, CAT1_MAX_TMPBFLEN);
					
					res = CAT1_CMD_OK;
					goto cmd_process_return;
				}
				
				res = CAT1_CMD_UNKNOWN1;
				goto cmd_process_return;
			}
    }
		
		if(cmd_retry <= 0)
		{
			res = CAT1_CMD_TIMEOUT;
			goto cmd_process_return;
		}
  }
	
cmd_process_return:
	
	Cat1_WorkMode = CAT1_MODE_TRS;
	
  return res;
}

void Cat1_PowerOff(void)
{
  Cat1_Power(0);
  Cat1_Reset(0);
}

uint8_t Cat1_ResetUp(void)
{
  uint8_t err, retry;
  
  for(retry=0; retry<3; retry++)
  {
    Cat1_PowerOff();
    
    vTaskDelay(500);
    
    err = cat1_powerup_wait_stmsg();
    if(err == 0)
    {
      return 0;
    }
  }
  
  return err;
}

uint8_t Cat1_WaitScoketALink(void)
{
  uint8_t err = (ERROR_PART3 + 1);
  uint16_t retry;
  
	cat1_cmd_process(&cat1_cmd_ppp, NULL);  /* +++ */
	
	cat1_cmd_process(&cat1_cmd_a, NULL);    /* a */
  
  for(retry=0; retry<1200; retry++)
  {
    err = (ERROR_PART3 + 2);
    
    if(cat1_cmd_process(&cat1_cmd_sysinfo, NULL) == CAT1_CMD_OK)
    {
      strncpy(Cat1_DynamicInfo.syslink, tmpbf, CAT1_MAX_TMPBFLEN);
      SysDbgLog("GM5 NET:%s\r\n", Cat1_DynamicInfo.syslink);
    }
    
    if(cat1_cmd_process(&enet_cmd_csq, NULL) == CAT1_CMD_OK)
    {
      strncpy(Cat1_DynamicInfo.csq, tmpbf, CAT1_MAX_TMPBFLEN);
      SysDbgLog("GM5 CSQ:%s\r\n", Cat1_DynamicInfo.csq);
    }
   
    if(cat1_cmd_process(&cat1_cmd_sockalk, NULL) == CAT1_CMD_OK)
    {
      if(strstr(tmpbf, "Connected") != NULL)
      {
        LED_MQTT_Connect(LED_ON);
        err = 0;
        break;
      }
    }
    
    if(retry < 300)                           /* 1m */
    {
      LED_MQTT_Connect_Toggle();
      vTaskDelay(200);
    }
    else if((retry >= 300) && (retry < 600))  /* 2m */
    {
      LED_MQTT_Connect_Toggle();
      vTaskDelay(400);
    }
    else if((retry >= 600) && (retry < 900))  /* 4m */
    {
      LED_MQTT_Connect_Toggle();
      vTaskDelay(800);
    }
    else if((retry >= 900) && (retry < 1200)) /* 8m */
    {
      LED_MQTT_Connect_Toggle();
      vTaskDelay(1600);
    }
  }
  
  if(cat1_cmd_process(&cat1_cmd_entm, NULL) != CAT1_CMD_OK)
  {
    err = (ERROR_PART3 + 3);
  }

  return err;
}

static uint8_t cat1_config_once(void)
{
	uint8_t need_rboot = 0;
  
	/* +++ */
	cat1_cmd_process(&cat1_cmd_ppp, NULL);
	
	/* a */
  cat1_cmd_process(&cat1_cmd_a, NULL);
	
	/* AT+E */
	if(cat1_cmd_process(&cat1_cmd_e, NULL) != CAT1_CMD_OK)
  {
    return (ERROR_PART2 + 1);
  }
  
	switch(cat1_cmd_process(&cat1_cmd_check_wkmod, Cat1_CfgPara.wkmod))
	{
		case CAT1_CMD_ERRCHECK:
			need_rboot = 1;
			if(cat1_cmd_process(&cat1_cmd_set_wkmod, Cat1_CfgPara.wkmod) != CAT1_CMD_OK)
      {
        return (ERROR_PART2 + 2);
      }
		case CAT1_CMD_OK:
			break;
		default:
			return (ERROR_PART2 + 2);
	}
  
	switch(cat1_cmd_process(&cat1_cmd_check_cmdpw, Cat1_CfgPara.cmdpw))
	{
		case CAT1_CMD_ERRCHECK:
			need_rboot = 1;
			if(cat1_cmd_process(&cat1_cmd_set_cmdpw, Cat1_CfgPara.cmdpw) != CAT1_CMD_OK)
      {
        return (ERROR_PART2 + 3);
      }
		case CAT1_CMD_OK:
			break;
		default:
			return (ERROR_PART2 + 3);
	}
  
	switch(cat1_cmd_process(&cat1_cmd_check_rstim, Cat1_CfgPara.rstim))
	{
		case CAT1_CMD_ERRCHECK:
			need_rboot = 1;
			if(cat1_cmd_process(&cat1_cmd_set_rstim, Cat1_CfgPara.rstim) != CAT1_CMD_OK)
      {
        return (ERROR_PART2 + 4);
      }
		case CAT1_CMD_OK:
			break;
		default:
			return (ERROR_PART2 + 4);
	}
  
	switch(cat1_cmd_process(&cat1_cmd_check_spden, Cat1_CfgPara.spden))
	{
		case CAT1_CMD_ERRCHECK:
			need_rboot = 1;
			if(cat1_cmd_process(&cat1_cmd_set_spden, Cat1_CfgPara.spden) != CAT1_CMD_OK)
      {
        return (ERROR_PART2 + 5);
      }
		case CAT1_CMD_OK:
			break;
		default:
			return (ERROR_PART2 + 5);
	}
  
	switch(cat1_cmd_process(&cat1_cmd_check_naten, Cat1_CfgPara.naten))
	{
		case CAT1_CMD_ERRCHECK:
			need_rboot = 1;
			if(cat1_cmd_process(&cat1_cmd_set_naten, Cat1_CfgPara.naten) != CAT1_CMD_OK)
      {
        return (ERROR_PART2 + 6);
      }
		case CAT1_CMD_OK:
			break;
		default:
			return (ERROR_PART2 + 6);
	}
  
	switch(cat1_cmd_process(&cat1_cmd_check_uaten, Cat1_CfgPara.uaten))
	{
		case CAT1_CMD_ERRCHECK:
			need_rboot = 1;
			if(cat1_cmd_process(&cat1_cmd_set_uaten, Cat1_CfgPara.uaten) != CAT1_CMD_OK)
      {
        return (ERROR_PART2 + 7);
      }
		case CAT1_CMD_OK:
			break;
		default:
			return (ERROR_PART2 + 7);
	}
  
	if(cat1_cmd_process(&cat1_cmd_ver, NULL) == CAT1_CMD_OK)
	{
    strncpy(Cat1_StaticInfo.ver, tmpbf, CAT1_MAX_TMPBFLEN);
    SysDbgLog("GM5 Ver:%s\r\n", Cat1_StaticInfo.ver);
	}
	
	if(cat1_cmd_process(&enet_cmd_sn, NULL) == CAT1_CMD_OK)
	{
    strncpy(Cat1_StaticInfo.sn, tmpbf, CAT1_MAX_TMPBFLEN);
    SysDbgLog("GM5 SN:%s\r\n", Cat1_StaticInfo.sn);
	}
  
	if(cat1_cmd_process(&enet_cmd_imei, NULL) == CAT1_CMD_OK)
	{
    strncpy(Cat1_StaticInfo.imei, tmpbf, CAT1_MAX_TMPBFLEN);
    SysDbgLog("GM5 IMEI:%s\r\n", Cat1_StaticInfo.imei);
	}
	
//	switch(cat1_cmd_process(&cat1_cmd_check_cachen, Cat1_CfgPara.cachen))
//	{
//    case CAT1_CMD_ERRCHECK:
//			need_rboot = 1;
//			if(cat1_cmd_process(&cat1_cmd_set_cachen, Cat1_CfgPara.cachen) != CAT1_CMD_OK)
//      {
//        return;
//      }
//		case CAT1_CMD_OK:
//			break;
//		default:
//			return;
//	}
	
	switch(cat1_cmd_process(&cat1_cmd_check_uartfl, Cat1_CfgPara.uartfl))
	{
		case CAT1_CMD_ERRCHECK:
			need_rboot = 1;
			if(cat1_cmd_process(&cat1_cmd_set_uartfl, Cat1_CfgPara.uartfl) != CAT1_CMD_OK)
      {
        return (ERROR_PART2 + 8);
      }
    case CAT1_CMD_OK:
			break;
		default:
			return (ERROR_PART2 + 8);
	}
  
  switch(cat1_cmd_process(&cat1_cmd_check_uartft, Cat1_CfgPara.uartft))
	{
    case CAT1_CMD_ERRCHECK:
			need_rboot = 1;
			if(cat1_cmd_process(&cat1_cmd_set_uartft, Cat1_CfgPara.uartft) != CAT1_CMD_OK)
      {
        return (ERROR_PART2 + 9);
      }
    case CAT1_CMD_OK:
			break;
		default:
			return (ERROR_PART2 + 9);
	}
  
  switch(cat1_cmd_process(&cat1_cmd_check_sockaen, Cat1_CfgPara.sockaen))
	{
    case CAT1_CMD_ERRCHECK:
			need_rboot = 1;
			if(cat1_cmd_process(&cat1_cmd_set_sockaen, Cat1_CfgPara.sockaen) != CAT1_CMD_OK)
      {
        return (ERROR_PART2 + 10);
      }
    case CAT1_CMD_OK:
			break;
		default:
			return (ERROR_PART2 + 10);
	}
  
  switch(cat1_cmd_process(&cat1_cmd_check_sockben, Cat1_CfgPara.sockben))
	{
    case CAT1_CMD_ERRCHECK:
			need_rboot = 1;
      if(cat1_cmd_process(&cat1_cmd_set_sockben, Cat1_CfgPara.sockben) != CAT1_CMD_OK)
      {
        return (ERROR_PART2 + 11);
      }
    case CAT1_CMD_OK:
			break;
		default:
			return (ERROR_PART2 + 11);
	}
	
	switch(cat1_cmd_process(&cat1_cmd_check_socka, Cat1_CfgPara.socka))
	{
    case CAT1_CMD_ERRCHECK:
			need_rboot = 1;
			if(cat1_cmd_process(&cat1_cmd_set_socka, Cat1_CfgPara.socka) != CAT1_CMD_OK)
      {
        return (ERROR_PART2 + 12);
      }
    case CAT1_CMD_OK:
			break;
		default:
			return (ERROR_PART2 + 12);
	}
  
  switch(cat1_cmd_process(&cat1_cmd_check_sockasl, Cat1_CfgPara.sockasl))
	{
    case CAT1_CMD_ERRCHECK:
			need_rboot = 1;
      if(cat1_cmd_process(&cat1_cmd_set_sockasl, Cat1_CfgPara.sockasl) != CAT1_CMD_OK)
      {
        return (ERROR_PART2 + 13);
      }
    case CAT1_CMD_OK:
			break;
		default:
			return (ERROR_PART2 + 13);
	}
  
  switch(cat1_cmd_process(&cat1_cmd_check_sockrstim, Cat1_CfgPara.sockrstim))
	{
    case CAT1_CMD_ERRCHECK:
			need_rboot = 1;
      if(cat1_cmd_process(&cat1_cmd_set_sockrstim, Cat1_CfgPara.sockrstim) != CAT1_CMD_OK)
      {
        return (ERROR_PART2 + 14);
      }
    case CAT1_CMD_OK:
			break;
		default:
			return (ERROR_PART2 + 14);
	}
  
	switch(cat1_cmd_process(&cat1_cmd_check_regen, Cat1_CfgPara.regen))
	{
    case CAT1_CMD_ERRCHECK:
			need_rboot = 1;
      if(cat1_cmd_process(&cat1_cmd_set_regen, Cat1_CfgPara.regen) != CAT1_CMD_OK)
      {
        return (ERROR_PART2 + 15);
      }
    case CAT1_CMD_OK:
			break;
		default:
			return (ERROR_PART2 + 15);
	}
	
	/* HEARTEN */
  switch(cat1_cmd_process(&cat1_cmd_check_hearten, Cat1_CfgPara.hearten))
	{
    case CAT1_CMD_ERRCHECK:
			need_rboot = 1;
      if(cat1_cmd_process(&cat1_cmd_set_hearten, Cat1_CfgPara.hearten) != CAT1_CMD_OK)
      {
        return (ERROR_PART2 + 16);
      }
    case CAT1_CMD_OK:
			break;
		default:
			return (ERROR_PART2 + 16);
	}
	
  if(cat1_cmd_process(&enet_cmd_iccid, NULL) == CAT1_CMD_OK)
	{
    if(strlen(tmpbf) < 5)
    {
      strncpy(Cat1_StaticInfo.iccid, "ERROR!", CAT1_MAX_TMPBFLEN);
      SysDbgLog("GM5 ICCID:%s\r\n", Cat1_StaticInfo.iccid);
      
      return (ERROR_PART2 + 17);
    }
    else
    {
      strncpy(Cat1_StaticInfo.iccid, tmpbf, CAT1_MAX_TMPBFLEN);
      SysDbgLog("GM5 ICCID:%s\r\n", Cat1_StaticInfo.iccid);
    }
	}
  
	if(need_rboot != 0)
	{
    if(cat1_cmd_process(&cat1_cmd_s, NULL) != CAT1_CMD_OK)
    {
      return (ERROR_PART2 + 18);
    }
		
		if(cat1_powerup_wait_stmsg() != CAT1_CMD_OK)
    {
      return (ERROR_PART2 + 19);
    }
	}
	else
	{
    if(cat1_cmd_process(&cat1_cmd_entm, NULL) != CAT1_CMD_OK)
    {
      return (ERROR_PART2 + 20);
    }
	}
  
  return 0;
}

uint8_t Cat1_StaticConfig(void)
{
  uint8_t err = 1;
  uint8_t retry;
  
  cat1_init();
  
  for(retry=0; retry<3; retry++)
  {
    err = Cat1_ResetUp();
    if(err == 0)
    {
      err = cat1_config_once();
      if(err == 0)
      {
        SysDbgLog("GM5 Successfully configured.\r\n");
        vTaskDelay(200);
        return 0;
      }
      else
      {
        SysDbgLog("GM5 Configuration failed!!! retry:%u, err:%u\r\n", retry, err);
      }
    }
    else
    {
      SysDbgLog("GM5 Cannot be detected!!! retry:%u, err:%u\r\n", retry, err);
    }
    
    vTaskDelay(500);
  }
  
  return err;
}

uint8_t Cat1_DynamicConfig(void)
{
  uint8_t err = 0;
  
	if(cat1_cmd_process(&cat1_cmd_ppp, NULL) != CAT1_CMD_OK)  /* +++ */
  {
    return 1;
  }
	
	if(cat1_cmd_process(&cat1_cmd_a, NULL) != CAT1_CMD_OK)    /* a */
  {
    return 2;
  }
  
  err = 0;
  
  if(cat1_cmd_process(&cat1_cmd_sysinfo, NULL) == CAT1_CMD_OK)
  {
    strncpy(Cat1_DynamicInfo.syslink, tmpbf, CAT1_MAX_TMPBFLEN);
    SysDbgLog("GM5 NET:%s\r\n", Cat1_DynamicInfo.syslink);
  }
  
  if(cat1_cmd_process(&enet_cmd_csq, NULL) == CAT1_CMD_OK)
  {
    strncpy(Cat1_DynamicInfo.csq, tmpbf, CAT1_MAX_TMPBFLEN);
    SysDbgLog("GM5 CSQ:%s\r\n", Cat1_DynamicInfo.csq);
  }
 
  if(cat1_cmd_process(&cat1_cmd_sockalk, NULL) == CAT1_CMD_OK)
  {
    if(strstr(tmpbf, "Connected") == NULL)
    {
      err = 3;
    }
  }
  
  if(cat1_cmd_process(&cat1_cmd_entm, NULL) != CAT1_CMD_OK)
  {
    err = 4;
  }
  
  vTaskDelay(50);
  
  return err;
}

void Cat1_CmdRcvISR(uint8_t dat)
{
	cat1_cmdisr_Buf.buf[cat1_cmdisr_Buf.count++] = dat;
	if(cat1_cmdisr_Buf.count > CAT1_CMDBUF_MAXLEN)
	{
		if(cat1_cmdque_qhd != NULL)   /* make sure tasks are created */
		{
			xQueueSendFromISR(cat1_cmdque_qhd, &cat1_cmdisr_Buf, NULL);
			cat1_cmdisr_Buf.count = 0;
		}
	}
}

void Cat1_CmdTimISR(void)
{
	if(cat1_cmdque_qhd != NULL)   /* make sure tasks are created */
	{
		xQueueSendFromISR(cat1_cmdque_qhd, &cat1_cmdisr_Buf, NULL);
		cat1_cmdisr_Buf.count = 0;
	}
}

void Cat1_LinkISR(void)
{
	if(Cat1_LinkA() == 0)
	{
    if(Cat1_WorkMode != CAT1_MODE_CMD)
    {
      MQTT_Context.connectStatus = MQTTNotConnected;
    }
		LED_MQTT_Connect(LED_OFF);
	}
}
